#include "scheduler_mfqs.h"

Scheduler_MFQS :: Scheduler_MFQS (int num_q, int time_quantum, int aging_time) {
	vector<MFQueue> queues;
	MFBase last_queue(aging_time);
	num_queues = num_q;
	clock = 0;
	
	if(num_queues < 1) {
		num_queues = 1;
	} else if(num_queues > 5) {
		num_queues = 5;
	}
	
	for(int i = 0; i < (num_queues - 1); i++) {
		MFQueue tmp ((i + 1) * time_quantum);
		queues.push_back(tmp);
	}
}

Scheduler_MFQS :: ~Scheduler_MFQS () {
}

void Scheduler_MFQS :: begin(list<Process> * procs) {
	processes = *procs;
	do {
		//Check if process has arrived
		fill_queue(clock);
		Process null;
		Process ran;
		if(num_queues > 1 && !queues[0].is_empty()) {
			ran.clone(run_processes(0));
			if(!(ran == null) && !ran.is_done()) {
				if(num_queues > 2) {
					queues[1].add_process(ran);
				} else {
					ran.wait_at(clock + 1);
					last_queue.add_process(ran);
				}
			}
		} else if(num_queues > 2 && !queues[1].is_empty()){
			ran.clone(run_processes(1));
			if(!(ran == null) && !ran.is_done()) {
				if(num_queues > 3) {
					queues[2].add_process(ran);
				} else {
					ran.wait_at(clock + 1);
					last_queue.add_process(ran);
				}
			}
		} else if(num_queues > 3 && !queues[2].is_empty()){
			ran.clone(run_processes(2));
			if(!(ran == null) && !ran.is_done()) {
				if(num_queues > 4) {
					queues[3].add_process(ran);
				} else {
					ran.wait_at(clock + 1);
					last_queue.add_process(ran);
				}
			}
		} else if(num_queues > 4 && !queues[3].is_empty()){
			ran.clone(run_processes(3));
			if(!(ran == null) && !ran.is_done()) {
				last_queue.add_process(ran);
			}
		} else if(!last_queue.is_empty()) {
			ran.clone(run_processes(-1));
			if(!(ran == null) && !ran.is_done()) {
				last_queue.add_process(ran);
			}
		}
		
		if(!last_queue.is_empty()) {
			queues[num_queues - 2].add_processes(last_queue.get_aged_processes(clock));
		}
		
		clock++;
	} while(queues_not_empty());
		
	for(int i = 0; i < (int)queues.size(); i++) {
		queues[i].print_gantt();
	}
	last_queue.print_gantt();
}

Process Scheduler_MFQS :: run_processes(int index) {
	Process result;
	
	for(int i = 0; i < (int)queues.size(); i++) {
		if(i == index) {
			result.clone(queues[i].run_next_process(true));
		} else {
			queues[i].run_next_process(false);
		}
	}
	if(index == -1) {
		result.clone(last_queue.run_next_process(true, clock));
	} else {
		last_queue.run_next_process(false, clock);
	}
	
	return result;
}

void Scheduler_MFQS :: fill_queue(int clk) {
	list<Process>::iterator itr;
	for(itr = processes.begin(); itr != processes.end(); itr++) {
		if(itr -> has_arrived(clk) && !queues[0].contains(*itr)) {
			Process tmp (*itr);
			queues[0].add_process(tmp);
			remove(processes.begin(), processes.end(), *itr);
		}
	}
}

bool Scheduler_MFQS :: queues_not_empty() {
	bool result = false;
	
	if(!processes.empty()) {
		result = true;
	} else {
		for(int i = 0; i < (int)queues.size(); i++) {
			if(!queues[i].is_empty()) {
				result = true;
				break;
			}
		}
	}
	if(!last_queue.is_empty()) {
		result = true;
	}
	
	return result;
}

